package com.redepronik.negosys.rrhh.service;

import static com.redepronik.negosys.utils.Utils.presentaMensaje;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.faces.application.FacesMessage;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.redepronik.negosys.invfac.entityAux.PersonaCedulaNombre;
import com.redepronik.negosys.rrhh.dao.PersonaDao;
import com.redepronik.negosys.rrhh.entity.Emailpersona;
import com.redepronik.negosys.rrhh.entity.Persona;
import com.redepronik.negosys.rrhh.entity.Telefonopersona;
import com.redepronik.negosys.seguridad.entity.Usuario;
import com.redepronik.negosys.seguridad.service.UsuarioService;

@Service
public class PersonaServiceImpl implements PersonaService, Serializable {

	private static final long serialVersionUID = 1L;

	@Autowired
	private PersonaDao personaDao;

	@Autowired
	private UsuarioService usuarioService;

	private ValidatorFactory factory = Validation
			.buildDefaultValidatorFactory();
	private Validator validator = factory.getValidator();

	public boolean actualizar(Persona persona) {
		boolean retorno = false;

		Set<ConstraintViolation<Persona>> violations = validator
				.validate(persona);
		if (violations.size() > 0)
			for (ConstraintViolation<Persona> cv : violations)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
		else if (persona.getCiudad().getCiudadid() == null
				|| persona.getCiudad().getCiudadid() == 0)
			presentaMensaje(FacesMessage.SEVERITY_INFO, "ESCOJA UNA CIUDAD");
		// } else if (persona.getEmailpersonas().size() == 0) {
		// presentaMensaje(FacesMessage.SEVERITY_INFO,
		// "MENSAJE DEL SISTEMA", "DEBE INGRESAR AL MENOS UN EMAIL"));
		else if (comprobarEmailsVacios(persona.getEmailpersonas()))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE REGISTROS DE CORREO VACIOS");
		// } else if (persona.getTelefonopersonas().size() == 0) {
		// presentaMensaje(FacesMessage.SEVERITY_INFO,
		// "MENSAJE DEL SISTEMA",
		// "DEBE INGRESAR AL MENOS UN TELÉFONO"));
		else if (comprobarTelefonosVacios(persona.getTelefonopersonas()))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE REGISTROS TELEFÓNICOS VACIOS");
		else if (personaDao.comprobarIndices(Persona.class, "cedula",
				persona.getCedula(), String.valueOf(persona.getPersonaid())))
			presentaMensaje(FacesMessage.SEVERITY_INFO, "LA CÉDULA YA EXISTE",
					"cerrar", false);
		else {
			int c = 1;
			for (Telefonopersona tp : persona.getTelefonopersonas()) {
				tp.setOrden(c++);
				tp.setPersona(persona);
			}
			c = 1;
			for (Emailpersona ep : persona.getEmailpersonas()) {
				ep.setOrden(c++);
				ep.setPersona(persona);
			}
			if (persona.getUsuario() == null) {
				persona.setUsuario(new Usuario());
				persona.getUsuario().setPersona(persona);
				persona.getUsuario().setNombre(
						persona.getApellido() + " " + persona.getNombre());
				persona.getUsuario().setLogin(persona.getCedula());
				persona.getUsuario().setPassword(
						usuarioService.generarClave(persona.getCedula()));
				persona.getUsuario().setEnabled(true);
			} else {
				persona.getUsuario().setLogin(persona.getCedula());
				persona.getUsuario().setNombre(
						persona.getApellido() + " " + persona.getNombre());
			}
			personaDao.actualizar(persona);
			retorno = true;
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"PERSONA ACTUALIZADA DE MANERA CORRECTA", "cerrar", true);
		}
		return retorno;
	}

	public void añadirFilaEmail(Persona persona) {
		if (persona.getEmailpersonas() == null) {// nulo
			persona.setEmailpersonas(new ArrayList<Emailpersona>());
			Emailpersona emailpersona = new Emailpersona();
			emailpersona.setEmail("@");
			persona.addEmailpersona(emailpersona);
		} else if (persona.getEmailpersonas().isEmpty()) {// inicializado
			Emailpersona emailpersona = new Emailpersona();
			emailpersona.setEmail("@");
			persona.addEmailpersona(emailpersona);
		} else {// con datos
			int size = persona.getEmailpersonas().size() - 1;
			String email = persona.getEmailpersonas().get(size).getEmail();
			if (email.length() > 1 && email.compareToIgnoreCase("@") != 0) {
				Emailpersona emailpersona = new Emailpersona();
				emailpersona.setEmail("@");
				persona.addEmailpersona(emailpersona);
			}
		}
	}

	public void añadirFilaTelefono(Persona persona) {
		if (persona.getTelefonopersonas() == null) {// nulo
			persona.setTelefonopersonas(new ArrayList<Telefonopersona>());
			Telefonopersona telefonopersona = new Telefonopersona();
			telefonopersona.setTelefono("593");
			persona.addTelefonopersona(telefonopersona);
		} else if (persona.getTelefonopersonas().isEmpty()) {// inicializado
			Telefonopersona telefonopersona = new Telefonopersona();
			telefonopersona.setTelefono("593");
			persona.addTelefonopersona(telefonopersona);
		} else {// con datos
			int size = persona.getTelefonopersonas().size() - 1;
			String fono = persona.getTelefonopersonas().get(size).getTelefono();
			if (fono.length() > 3 && fono.compareToIgnoreCase("593") != 0) {
				Telefonopersona telefonopersona = new Telefonopersona();
				telefonopersona.setTelefono("593");
				persona.addTelefonopersona(telefonopersona);
			}
		}
	}

	public Persona completarTelefono(Persona persona) {
		List<Telefonopersona> list = persona.getTelefonopersonas();
		if (!list.isEmpty())
			for (Telefonopersona telefonopersona : list) {
				String fono = telefonopersona.getTelefono();
				if (fono.length() == 6 || fono.length() == 7)
					if (String.valueOf(fono.charAt(0)).equals("2")) {
						fono = fono.substring(1, fono.length());
						fono = "072" + fono;
						telefonopersona.setTelefono(fono);
					} else {
						fono = "072" + fono;
						telefonopersona.setTelefono(fono);
					}
			}
		return persona;
	}

	public void comprobarEmail(Persona persona, Emailpersona email) {
		Set<ConstraintViolation<Emailpersona>> violationsEmailPersona = validator
				.validate(email);

		if (violationsEmailPersona.size() > 0) {
			for (ConstraintViolation<Emailpersona> cv : violationsEmailPersona) {
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
			}
			persona.getEmailpersonas()
					.get(persona.getEmailpersonas().indexOf(email))
					.setEmail(new String());
		} else {
			persona.getEmailpersonas()
					.get(persona.getEmailpersonas().indexOf(email))
					.setEmail(email.getEmail().toUpperCase());
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"EMAIL AGREGADO CORRECTAMENTE");
		}
	}

	public Boolean comprobarEmailsVacios(List<Emailpersona> listaEmails) {
		boolean bep = false;
		for (Emailpersona ep : listaEmails) {
			if ((ep.getEmail() == null)
					|| (ep.getEmail() != null && ep.getEmail()
							.compareToIgnoreCase("") == 0)) {
				bep = true;
				break;
			}
		}
		return bep;
	}

	public void comprobarTelefono(Persona persona, Telefonopersona telefono) {
		Set<ConstraintViolation<Telefonopersona>> violationsTelefonoPersona = validator
				.validate(telefono);

		if (violationsTelefonoPersona.size() > 0) {
			for (ConstraintViolation<Telefonopersona> cv : violationsTelefonoPersona) {
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());
			}
			persona.getTelefonopersonas()
					.get(persona.getTelefonopersonas().indexOf(telefono))
					.setTelefono(new String());
			persona.getTelefonopersonas()
					.get(persona.getTelefonopersonas().indexOf(telefono))
					.setReferencia(new String());
		} else {
			if (telefono.getReferencia() != null)
				persona.getTelefonopersonas()
						.get(persona.getTelefonopersonas().indexOf(telefono))
						.setReferencia(telefono.getReferencia().toUpperCase());

			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TELÉFONO AGREGADO CORRECTAMENTE");
		}
	}

	public Boolean comprobarTelefonosVacios(List<Telefonopersona> listaTelefonos) {
		boolean btp = false;
		for (Telefonopersona tp : listaTelefonos) {
			if ((tp.getTelefono() == null)
					|| (tp.getTelefono() != null && tp.getTelefono()
							.compareToIgnoreCase("") == 0)) {
				btp = true;
				break;
			}
		}
		return btp;
	}

	public Long contar() {
		return (Long) personaDao.contar(Persona.class, "personaid");
	}

	public void eliminar(Persona persona) {
		persona.setActivo(persona.getActivo() ? false : true);
		persona.getUsuario().setEnabled(persona.getActivo() ? false : true);
		personaDao.actualizar(persona);

		if (persona.getActivo())
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE ACTIVO A LA PERSONA: " + persona.getApellido() + " "
							+ persona.getNombre());
		else
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE DESACTIVO A LA PERSONA: " + persona.getApellido() + " "
							+ persona.getNombre());
	}

	public void eliminarEmail(Persona persona, Emailpersona emailPersona) {
		if (persona.getEmailpersonas().size() > 1) {
			String email = emailPersona.getEmail();
			persona.removeEmailpersona(emailPersona);
			presentaMensaje(FacesMessage.SEVERITY_INFO, "SE ELIMINO EL EMAIL "
					+ email);
		} else {
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"DEBE TENER AL MENOS UN E-MAIL VÁLIDO");
		}
	}

	public void eliminarTelefono(Persona persona,
			Telefonopersona telefonoPersona) {
		if (persona.getTelefonopersonas().size() > 1) {
			String telefono = telefonoPersona.getTelefono();
			persona.removeTelefonopersona(telefonoPersona);
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"SE ELIMINO EL TELEFONO " + telefono);
		} else {
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"DEBE TENER AL MENOS UN TELÉFONO VÁLIDO");
		}
	}

	public void eliminartelefonoEmail(Persona persona) {
		if (!persona.getTelefonopersonas().isEmpty()) {
			int sizeFono = persona.getTelefonopersonas().size() - 1;
			String fono = persona.getTelefonopersonas().get(sizeFono)
					.getTelefono();
			if (fono.length() == 3 && fono.compareToIgnoreCase("593") == 0)
				persona.getTelefonopersonas().remove(sizeFono);
		}
		if (!persona.getEmailpersonas().isEmpty()) {
			int sizeEmail = persona.getEmailpersonas().size() - 1;
			String email = persona.getEmailpersonas().get(sizeEmail).getEmail();
			if (email.length() == 1 && email.compareToIgnoreCase("@") == 0)
				persona.getEmailpersonas().remove(sizeEmail);
		}
	}

	public boolean insertar(Persona persona) {
		boolean retorno = false;
		persona.setFecharegistro(new Date());
		persona.setActivo(true);

		Set<ConstraintViolation<Persona>> violationsPersona = validator
				.validate(persona);
		if (violationsPersona.size() > 0)
			for (ConstraintViolation<Persona> cv : violationsPersona)
				presentaMensaje(FacesMessage.SEVERITY_INFO, cv.getMessage());

		else if (persona.getCiudad().getCiudadid() == null
				|| persona.getCiudad().getCiudadid() == 0)
			presentaMensaje(FacesMessage.SEVERITY_INFO, "ESCOJA UNA CIUDAD");
		// } else if (persona.getEmailpersonas().size() == 0) {
		// presentaMensaje(FacesMessage.SEVERITY_INFO,
		// "MENSAJE DEL SISTEMA", "DEBE INGRESAR AL MENOS UN EMAIL"));
		else if (comprobarEmailsVacios(persona.getEmailpersonas()))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE REGISTROS DE CORREO VACIOS");
		// } else if (persona.getTelefonopersonas().size() == 0) {
		// presentaMensaje(FacesMessage.SEVERITY_INFO,
		// "MENSAJE DEL SISTEMA",
		// "DEBE INGRESAR AL MENOS UN TELÉFONO"));
		else if (comprobarTelefonosVacios(persona.getTelefonopersonas()))
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"TIENE REGISTROS TELEFÓNICOS VACIOS");
		else if (personaDao.comprobarIndices(Persona.class, "cedula",
				persona.getCedula(), String.valueOf(persona.getPersonaid())))
			presentaMensaje(FacesMessage.SEVERITY_INFO, "LA CÉDULA YA EXISTE",
					"cerrar", false);
		else {
			int c = 1;
			for (Telefonopersona tp : persona.getTelefonopersonas()) {
				tp.setOrden(c++);
				tp.setPersona(persona);
			}

			c = 1;
			for (Emailpersona ep : persona.getEmailpersonas()) {
				ep.setOrden(c++);
				ep.setPersona(persona);
			}

			persona.setUsuario(new Usuario());
			persona.getUsuario().setPersona(persona);
			persona.getUsuario().setNombre(
					persona.getApellido() + " " + persona.getNombre());
			persona.getUsuario().setLogin(persona.getCedula());
			persona.getUsuario().setPassword(
					usuarioService.generarClave(persona.getCedula()));
			persona.getUsuario().setEnabled(true);
			personaDao.insertar(persona);
			retorno = true;
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"PERSONA INSERTADA DE MANERA CORRECTA", "cerrar", true);
		}
		return retorno;
	}

	public FacesMessage insertarEmail(Persona persona, Emailpersona emailPersona) {
		FacesMessage msg = null;
		boolean bn = true;
		int size = persona.getEmailpersonas().size() - 1;
		String email = persona.getEmailpersonas().get(size).getEmail();
		List<Emailpersona> list = new ArrayList<Emailpersona>();
		list.addAll(persona.getEmailpersonas());
		list.remove(size);
		for (Emailpersona tc : list)
			if (tc.getEmail().compareToIgnoreCase(email) == 0) {
				msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "ERROR",
						"EL E-MAIL YA ESTA AGREGADO");
				bn = false;
				break;
			}
		if (bn)
			añadirFilaEmail(persona);

		return msg;
	}

	public void insertarFilaEmail(Persona persona) {
		if (persona.getCedula().length() == 0)
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"INGRESE PRIMERO UNA CÉDULA VÁLIDA");
		else
			persona.getEmailpersonas().add(new Emailpersona());
	}

	public void insertarFilaTelefono(Persona persona) {
		if (persona.getCedula().length() == 0)
			presentaMensaje(FacesMessage.SEVERITY_INFO,
					"INGRESE PRIMERO UNA CÉDULA VÁLIDA");
		else
			persona.getTelefonopersonas().add(new Telefonopersona());
	}

	public FacesMessage insertarTelefono(Persona persona,
			Telefonopersona telefonoPersona) {
		FacesMessage msg = null;
		boolean bn = true;
		int size = persona.getTelefonopersonas().size() - 1;
		String fono = persona.getTelefonopersonas().get(size).getTelefono();
		List<Telefonopersona> list = new ArrayList<Telefonopersona>();
		list.addAll(persona.getTelefonopersonas());
		list.remove(size);
		for (Telefonopersona tc : list)
			if (tc.getTelefono().compareToIgnoreCase(fono) == 0) {
				msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "ERROR",
						"EL TELEFONO YA ESTA AGREGADO");
				bn = false;
				break;
			}
		if (bn)
			añadirFilaTelefono(persona);

		return msg;
	}

	public List<Persona> obtener(Boolean activo) {
		List<Persona> lista = personaDao.obtenerPorHql(
				"select p from Persona p order by p.apellido, p.nombre",
				new Object[] {});
		return lista;
	}

	public PersonaCedulaNombre obtenerPersonaCedulaNombre(String cedula) {
		return (PersonaCedulaNombre) personaDao
				.obtenerPorSql1(
						"select p.personaid as id, p.cedula as cedula, "
								+ "p.apellido||' '||p.nombre as nombres "
								+ "from rrhh.persona p where p.cedula='"
								+ cedula + "'", PersonaCedulaNombre.class).get(
						0);
	}

	public Persona obtenerPorCedula(String cedula) {
		List<Persona> persona = personaDao.obtenerPorHql(
				"select p from Persona p left join fetch p.emailpersonas "
						+ "left join fetch p.telefonopersonas "
						+ "where p.cedula=?1 and p.activo=true",
				new Object[] { cedula });
		if (persona != null)
			if (persona.size() != 0)
				return persona.get(0);

		return null;
	}

	public Persona obtenerPorPersonaId(Integer personaId) {
		Persona persona = personaDao.obtenerPorHql(
				"select p from Persona p left join fetch p.emailpersonas "
						+ "left join fetch p.telefonopersonas "
						+ "where p.personaid=?1 and p.activo=true",
				new Object[] { personaId }).get(0);
		return persona;
	}

	public List<Persona> obtenerTodosPorBusqueda(
			String criterioBusquedaPersona, int criterioBusquedaCiudad) {
		List<Persona> lista = null;

		if (criterioBusquedaPersona.compareToIgnoreCase("") == 0
				&& criterioBusquedaCiudad == 0)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE UN CRITERIO DE BUSQUEDA");
		else {
			if (criterioBusquedaPersona.length() >= 3
					|| criterioBusquedaCiudad != 0) {
				if (criterioBusquedaPersona.compareToIgnoreCase("") != 0
						&& criterioBusquedaCiudad != 0)
					lista = personaDao
							.obtenerPorHql(
									"select distinct p from Persona p "
											+ "left join fetch p.emailpersonas "
											+ "left join fetch p.telefonopersonas "
											+ "inner join p.ciudad cd "
											+ "where (cd.ciudadid=?2 "
											+ "and (p.cedula like ?1 or p.nombre like ?1 or p.apellido like ?1 )) "
											+ "order by p.apellido, p.nombre",
									new Object[] {
											"%" + criterioBusquedaPersona + "%",
											criterioBusquedaCiudad });
				else if (criterioBusquedaPersona.compareToIgnoreCase("") != 0)
					lista = personaDao
							.obtenerPorHql(
									"select distinct p from Persona p "
											+ "left join fetch p.emailpersonas "
											+ "left join fetch p.telefonopersonas "
											+ "where (p.cedula like ?1 or p.nombre like ?1 or p.apellido like ?1 ) "
											+ "order by p.apellido, p.nombre",
									new Object[] { "%"
											+ criterioBusquedaPersona + "%" });
				else if (criterioBusquedaCiudad != 0)
					lista = personaDao.obtenerPorHql(
							"select distinct p from Persona p "
									+ "left join fetch p.emailpersonas "
									+ "left join fetch p.telefonopersonas "
									+ "inner join p.ciudad cd "
									+ "where cd.ciudadid=?1 "
									+ "order by p.apellido, p.nombre",
							new Object[] { criterioBusquedaCiudad });
				if (lista.isEmpty())
					presentaMensaje(FacesMessage.SEVERITY_INFO,
							"NO SE ENCONTRO NINGUNA COINCIDENCIA");
			} else
				presentaMensaje(FacesMessage.SEVERITY_ERROR,
						"INGRESE MINIMO 3 CARACTERES");
		}
		return lista;
	}
}
